home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 1 / Cream of the Crop 1.iso / PROGRAM / INDENT3.ARJ / LEXI.C < prev    next >
C/C++ Source or Header  |  1992-08-04  |  15KB  |  542 lines

  1. /* Copyright (c) 1980 Regents of the University of California. All rights
  2.  * reserved.  The Berkeley software License Agreement specifies the terms and
  3.  * conditions for redistribution. */
  4.  
  5. #ifndef lint
  6. static char sccsid[] = "@(#)lexi.c    5.4 (Berkeley) 9/10/85";
  7. #endif not lint
  8.  
  9. /*-
  10.  *
  11.  *              Copyright (C) 1976
  12.  *                by the
  13.  *              Board of Trustees
  14.  *                of the
  15.  *            University of Illinois
  16.  *
  17.  *             All rights reserved
  18.  *
  19.  *
  20.  * NAME:
  21.  *    lexi
  22.  *
  23.  * FUNCTION:
  24.  *    This is the token scanner for indent
  25.  *
  26.  * ALGORITHM:
  27.  *    1) Strip off intervening blanks and/or tabs.
  28.  *    2) If it is an alphanumeric token, move it to the token buffer "token".
  29.  *       Check if it is a special reserved word that indent will want to
  30.  *       know about.
  31.  *    3) Non-alphanumeric tokens are handled with a big switch statement.  A
  32.  *       flag is kept to remember if the last token was a "unary delimiter",
  33.  *       which forces a following operator to be unary as opposed to binary.
  34.  *
  35.  * PARAMETERS:
  36.  *    None
  37.  *
  38.  * RETURNS:
  39.  *    An integer code indicating the type of token scanned.
  40.  *
  41.  * GLOBALS:
  42.  *    buf_ptr =
  43.  *    had_eof
  44.  *    ps.last_u_d =    Set to true iff this token is a "unary delimiter"
  45.  *
  46.  * CALLS:
  47.  *    fill_buffer
  48.  *    printf (lib)
  49.  *
  50.  * CALLED BY:
  51.  *    main
  52.  *
  53.  * NOTES:
  54.  *    Start of comment is passed back so that the comment can be scanned by
  55.  *    pr_comment.
  56.  *
  57.  *    Strings and character literals are returned just like identifiers.
  58.  *
  59.  * HISTORY:
  60.  *    initial coding     November 1976    D A Willcox of CAC
  61.  *    1/7/77        D A Willcox of CAC    Fix to provide proper handling
  62.  *                        of "int a -1;"
  63.  *
  64.  */
  65.  
  66. /* Here we have the token scanner for indent.  It scans off one token and
  67.  * puts it in the global variable "token".  It returns a code, indicating the
  68.  * type of token scanned. */
  69.  
  70. #include "indent_globs.h"
  71. #include <ctype.h>
  72.  
  73. #define alphanum 1
  74. #define opchar 3
  75.  
  76. struct templ {
  77.     char *rwd;
  78.     int rwcode;
  79. };
  80.  
  81. #define TABLE_SIZE 256
  82.  
  83. struct templ specials[TABLE_SIZE] =
  84. {
  85.     {"else", rw_sp_nparen,},
  86.     {"short", rw_decl,},
  87.     {"struct", rw_struct_like,},
  88.     {"extern", rw_decl,},
  89.     {"return", rw_break,},
  90.     {"while", rw_sp_paren,},
  91.     {"register", rw_decl,},
  92.     {"int", rw_decl,},
  93.     {"switch", rw_switch,},
  94.     {"case", rw_case,},
  95.     {"char", rw_decl,},
  96.     {"static", rw_decl,},
  97.     {"double", rw_decl,},
  98.     {"default", rw_case,},
  99.     {"union", rw_struct_like,},
  100.     {"for", rw_sp_paren,},
  101.     {"float", rw_decl,},
  102.     {"sizeof", rw_sizeof,},
  103.     {"typedef", rw_decl,},
  104.     {"enum", rw_struct_like,},
  105.     {"long", rw_decl,},
  106.     {"if", rw_sp_paren,},
  107.     {"global", rw_decl,},
  108.     {"va_dcl", rw_decl,},
  109.     {"do", rw_sp_nparen,},
  110.     {"break", rw_break,},
  111.     {"unsigned", rw_decl,},
  112.     {"void", rw_decl,},
  113.     {"goto", rw_break,},
  114.     {NULL, rw_none}
  115. };
  116.  
  117. char chartype[128] =
  118. {                /* this is used to facilitate the decision of
  119.                  * what type (alphanumeric, operator) each
  120.                  * character is */
  121.     0, 0, 0, 0, 0, 0, 0, 0,
  122.     0, 0, 0, 0, 0, 0, 0, 0,
  123.     0, 0, 0, 0, 0, 0, 0, 0,
  124.     0, 0, 0, 0, 0, 0, 0, 0,
  125.     0, 3, 0, 0, 0, 3, 3, 0,
  126.     0, 0, 3, 3, 0, 3, 3, 3,
  127.     1, 1, 1, 1, 1, 1, 1, 1,
  128.     1, 1, 0, 0, 3, 3, 3, 3,
  129.     0, 1, 1, 1, 1, 1, 1, 1,
  130.     1, 1, 1, 1, 1, 1, 1, 1,
  131.     1, 1, 1, 1, 1, 1, 1, 1,
  132.     1, 1, 1, 0, 0, 0, 3, 1,
  133.     0, 1, 1, 1, 1, 1, 1, 1,
  134.     1, 1, 1, 1, 1, 1, 1, 1,
  135.     1, 1, 1, 1, 1, 1, 1, 1,
  136.     1, 1, 1, 0, 3, 0, 3, 0
  137. };
  138.  
  139. enum codes
  140.   lexi()
  141. {
  142.     register char *tok;        /* local pointer to next char in token */
  143.     int unary_delim;        /* this is set to 1 if the current token 
  144.                  *
  145.                  * forces a following operator to be unary */
  146.     static int last_code;    /* the last token type returned */
  147.     static int l_struct;    /* set to 1 if the last token was 'struct' */
  148.     int code;            /* internal code to be returned */
  149.     char qchar;            /* the delimiter character for a string */
  150.  
  151.     tok = token;        /* point to start of place to save token */
  152.     unary_delim = false;
  153.     ps.col_1 = ps.last_nl;    /* tell world that this token started in
  154.                  * column 1 iff the last thing scanned was nl */
  155.     ps.last_nl = false;
  156.  
  157.     while (*buf_ptr == ' ' || *buf_ptr == '\t') {    /* get rid of blanks */
  158.     ps.col_1 = false;    /* leading blanks imply token is not in
  159.                  * column 1 */
  160.     if (++buf_ptr >= buf_end)
  161.         fill_buffer();
  162.     }
  163.  
  164.     /* Scan an alphanumeric token.  Note that we must also handle stuff like
  165.      * "1.0e+03" and "7e-6". */
  166.     if (chartype[*buf_ptr & 0177] == alphanum) {    /* we have a character
  167.                              * or number */
  168.     register char *j;    /* used for searching thru list of reserved
  169.                  * words */
  170.     register struct templ *p;
  171.     register int c;
  172.  
  173.     do {            /* copy it over */
  174.         *tok++ = *buf_ptr++;
  175.         if (buf_ptr >= buf_end)
  176.         fill_buffer();
  177.     } while (chartype[c = *buf_ptr & 0177] == alphanum ||
  178.         isdigit(token[0]) && (c == '+' || c == '-') &&
  179.         (tok[-1] == 'e' || tok[-1] == 'E'));
  180.     *tok++ = '\0';
  181.     while (*buf_ptr == ' ' || *buf_ptr == '\t') {    /* get rid of blanks */
  182.         if (++buf_ptr >= buf_end)
  183.         fill_buffer();
  184.     }
  185.     ps.its_a_keyword = false;
  186.     ps.sizeof_keyword = false;
  187.     if (l_struct) {        /* if last token was 'struct', then this
  188.                  * token should be treated as a declaration */
  189.         l_struct = false;
  190.         last_code = ident;
  191.         ps.last_u_d = true;
  192.         return (decl);
  193.     }
  194.     ps.last_u_d = false;    /* Operator after indentifier is binary */
  195.     last_code = ident;    /* Remember that this is the code we will
  196.                  * return */
  197.  
  198.     /* This loop will check if the token is a keyword. */
  199.     for (p = specials; (j = p->rwd) != NULL; p++) {
  200.         tok = token;    /* point at scanned token */
  201.         if (*j++ != *tok++ || *j++ != *tok++)
  202.         continue;    /* This test depends on the fact that
  203.                  * identifiers are always at least 1
  204.                  * character long (ie. the first two bytes of
  205.                  * the identifier are always meaningful) */
  206.         if (tok[-1] == '\0')
  207.         break;        /* If its a one-character identifier */
  208.         while (*tok++ == *j)
  209.         if (*j++ == '\0')
  210.             goto found_keyword;        /* I wish that C had a
  211.                          * multi-level break... */
  212.     }
  213.     if (p->rwd) {        /* we have a keyword */
  214.     found_keyword:
  215.         ps.its_a_keyword = true;
  216.         ps.last_u_d = true;
  217.         switch (p->rwcode) {
  218.         case rw_switch:/* it is a switch */
  219.             return (swstmt);
  220.         case rw_case:    /* a case or default */
  221.             return (casestmt);
  222.  
  223.         case rw_struct_like:    /* a "struct" */
  224.             if (ps.p_l_follow)
  225.             break;    /* inside parens: cast */
  226.             l_struct = true;
  227.  
  228.             /* Next time around, we will want to know that we have
  229.              * had a 'struct' */
  230.         case rw_decl:    /* one of the declaration keywords */
  231.             if (ps.p_l_follow) {
  232.             ps.cast_mask |= 1 << ps.p_l_follow;
  233.             break;    /* inside parens: cast */
  234.             }
  235.             last_code = decl;
  236.             return (decl);
  237.  
  238.         case rw_sp_paren:    /* if, while, for */
  239.             return (sp_paren);
  240.  
  241.         case rw_sp_nparen:    /* do, else */
  242.             return (sp_nparen);
  243.  
  244.         case rw_sizeof:
  245.             ps.sizeof_keyword = true;
  246.         default:    /* all others are treated like any other
  247.                  * identifier */
  248.             return (ident);
  249.         }            /* end of switch */
  250.     }            /* end of if (found_it) */
  251.     if (*buf_ptr == '(' && ps.tos <= 1 && ps.ind_level == 0
  252.         && (buf_ptr[1] != ')' || buf_ptr[2] != ';')) {
  253.         strncpy(ps.procname, token, sizeof ps.procname - 1);
  254.         ps.in_parameter_declaration = 1;
  255.     }
  256.     /* The following hack attempts to guess whether or not the current
  257.      * token is in fact a declaration keyword -- one that has been
  258.      * typedefd */
  259.     if (((*buf_ptr == '*' && buf_ptr[1] != '=') || isalpha(*buf_ptr))
  260.         && !ps.p_l_follow
  261.         && (ps.last_token == rparen || ps.last_token == semicolon ||
  262.         ps.last_token == decl ||
  263.         ps.last_token == lbrace || ps.last_token == rbrace)) {
  264.         ps.its_a_keyword = true;
  265.         ps.last_u_d = true;
  266.         last_code = decl;
  267.         return decl;
  268.     }
  269.     if (last_code == decl)    /* if this is a declared variable, then
  270.                  * following sign is unary */
  271.         ps.last_u_d = true;    /* will make "int a -1" work */
  272.     last_code = ident;
  273.     return (ident);        /* the ident is not in the list */
  274.     }                /* end of procesing for alpanum character */
  275.     /* l l o l f  f l o l Scan a non-alphanumeric token */
  276.  
  277.     *tok++ = *buf_ptr;        /* if it is only a one-character token, it is
  278.                  * moved here */
  279.     *tok = '\0';
  280.     if (++buf_ptr >= buf_end)
  281.     fill_buffer();
  282.  
  283.     switch (*token) {
  284.     case '\n':
  285.         unary_delim = ps.last_u_d;
  286.         ps.last_nl = true;    /* remember that we just had a newline */
  287.         code = (had_eof ? 0 : newline);
  288.  
  289.         /* if data has been exausted, the newline is a dummy, and we
  290.          * should return code to stop */
  291.         break;
  292.  
  293.     case '\'':        /* start of quoted character */
  294.     case '"':        /* start of string */
  295.         qchar = *token;
  296.         if (troff) {
  297.         tok[-1] = '`';
  298.         if (qchar == '"')
  299.             *tok++ = '`';
  300.         *tok++ = BACKSLASH;
  301.         *tok++ = 'f';
  302.         *tok++ = 'L';
  303.         }
  304.         do {        /* copy the string */
  305.         while (1) {    /* move one character or [/<char>]<char> */
  306.             if (*buf_ptr == '\n') {
  307.             printf("%d: Unterminated literal\n", line_no);
  308.             goto stop_lit;
  309.             }
  310.             *tok = *buf_ptr++;
  311.             if (buf_ptr >= buf_end)
  312.             fill_buffer();
  313.             if (had_eof || ((tok - token) > (bufsize - 2))) {
  314.             printf("Unterminated literal\n");
  315.             ++tok;
  316.             goto stop_lit;
  317.             /* get outof literal copying loop */
  318.             }
  319.             if (*tok == BACKSLASH) {    /* if escape, copy extra char */
  320.             if (*buf_ptr == '\n')    /* check for escaped newline */
  321.                 ++line_no;
  322.             if (troff) {
  323.                 *++tok = BACKSLASH;
  324.                 if (*buf_ptr == BACKSLASH)
  325.                 *++tok = BACKSLASH;
  326.             }
  327.             *++tok = *buf_ptr++;
  328.             ++tok;    /* we must increment this again because we
  329.                  * copied two chars */
  330.             if (buf_ptr >= buf_end)
  331.                 fill_buffer();
  332.             } else
  333.             break;    /* we copied one character */
  334.         }        /* end of while (1) */
  335.         } while (*tok++ != qchar);
  336.         if (troff) {
  337.         tok[-1] = BACKSLASH;
  338.         *tok++ = 'f';
  339.         *tok++ = 'R';
  340.         *tok++ = '\'';
  341.         if (qchar == '"')
  342.             *tok++ = '\'';
  343.         }
  344.     stop_lit:
  345.         code = ident;
  346.         break;
  347.  
  348.     case ('('):
  349.     case ('['):
  350.         unary_delim = true;
  351.         code = lparen;
  352.         break;
  353.  
  354.     case (')'):
  355.     case (']'):
  356.         code = rparen;
  357.         break;
  358.  
  359.     case '#':
  360.         unary_delim = ps.last_u_d;
  361.         code = preesc;
  362.         break;
  363.  
  364.     case '?':
  365.         unary_delim = true;
  366.         code = question;
  367.         break;
  368.  
  369.     case (':'):
  370.         code = colon;
  371.         unary_delim = true;
  372.         break;
  373.  
  374.     case (';'):
  375.         unary_delim = true;
  376.         code = semicolon;
  377.         break;
  378.  
  379.     case ('{'):
  380.         unary_delim = true;
  381.  
  382.         /* if (ps.in_or_st) ps.block_init = 1; */
  383.         code = ps.block_init ? lparen : lbrace;
  384.         break;
  385.  
  386.     case ('}'):
  387.         unary_delim = true;
  388.         code = ps.block_init ? rparen : rbrace;
  389.         break;
  390.  
  391.     case 014:        /* a form feed */
  392.         unary_delim = ps.last_u_d;
  393.         ps.last_nl = true;    /* remember this so we can set 'ps.col_1'
  394.                  * right */
  395.         code = form_feed;
  396.         break;
  397.  
  398.     case (','):
  399.         unary_delim = true;
  400.         code = comma;
  401.         break;
  402.  
  403.     case '.':
  404.         unary_delim = false;
  405.         code = period;
  406.         break;
  407.  
  408.     case '-':
  409.     case '+':        /* check for -, +, --, ++ */
  410.         code = (ps.last_u_d ? unary_op : binary_op);
  411.         unary_delim = true;
  412.  
  413.         if (*buf_ptr == token[0]) {
  414.         /* check for doubled character */
  415.         *tok++ = *buf_ptr++;
  416.         /* buffer overflow will be checked at end of loop */
  417.         if (last_code == ident || last_code == rparen) {
  418.             code = (ps.last_u_d ? unary_op : postop);
  419.             /* check for following ++ or -- */
  420.             unary_delim = false;
  421.         }
  422.         } else if (*buf_ptr == '=')
  423.         /* check for operator += */
  424.         *tok++ = *buf_ptr++;
  425.         else if (token[0] == '-' && *buf_ptr == '>') {
  426.         /* check for operator -> */
  427.         *tok++ = *buf_ptr++;
  428.         if (!pointer_as_binop) {
  429.             code = unary_op;
  430.             unary_delim = false;
  431.             ps.want_blank = false;
  432.         }
  433.         }
  434.         /* buffer overflow will be checked at end of switch */
  435.         break;
  436.  
  437.     case '=':
  438.         if (ps.in_or_st)
  439.         ps.block_init = 1;
  440. #if 0
  441.         if (chartype[*buf_ptr] == opchar) {        /* we have two char
  442.                              * assignment */
  443.         tok[-1] = *buf_ptr++;
  444.         if ((tok[-1] == '<' || tok[-1] == '>') && tok[-1] == *buf_ptr)
  445.             *tok++ = *buf_ptr++;
  446.         *tok++ = '=';    /* Flip =+ to += */
  447.         *tok = 0;
  448.         }
  449. #else
  450.         if (*buf_ptr == '=') {
  451.         *tok++ = *buf_ptr++;
  452.         *(tok) = 0;
  453.         }
  454. #endif
  455.         code = binary_op;
  456.         unary_delim = true;
  457.         break;
  458.         /* can drop thru!!! */
  459.     case '>':
  460.     case '<':
  461.     case '!':        /* ops like <, <<, <=, !=, etc */
  462.         if (*buf_ptr == '>' || *buf_ptr == '<' || *buf_ptr == '=') {
  463.         *tok++ = *buf_ptr;
  464.         if (++buf_ptr >= buf_end)
  465.             fill_buffer();
  466.         }
  467.         /* drop thru */
  468.     case '*':
  469.     case '/':
  470.     case '%':
  471.     case '^':
  472.  
  473.         /* *=, /=, %=, ^=, |=, &= */
  474.         if (*buf_ptr == '=')
  475.         *tok++ = *buf_ptr++;
  476.  
  477.         if (token[0] == '/' && *buf_ptr == '*') {
  478.         /* it is start of comment */
  479.         *tok++ = '*';
  480.  
  481.         if (++buf_ptr >= buf_end)
  482.             fill_buffer();
  483.  
  484.         code = comment;
  485.         unary_delim = ps.last_u_d;
  486.         break;
  487.         }
  488.         code = (ps.last_u_d ? unary_op : binary_op);
  489.         unary_delim = true;
  490.         break;
  491.  
  492.     case '|':
  493.     case '&':
  494.         /* |= &= */
  495.         if (*buf_ptr == '=' || *buf_ptr == tok[-1])
  496.         *tok++ = *buf_ptr++;
  497.         code = (ps.last_u_d ? unary_op : binary_op);
  498.         unary_delim = true;
  499.         break;
  500.  
  501.     default:
  502.         while (*(tok - 1) == *buf_ptr || *buf_ptr == '=') {
  503.         /* handle ||, &&, etc, and also things as in int *****i */
  504.         *tok++ = *buf_ptr;
  505.         if (++buf_ptr >= buf_end)
  506.             fill_buffer();
  507.         }
  508.         code = (ps.last_u_d ? unary_op : binary_op);
  509.         unary_delim = true;
  510.     }                /* end of switch */
  511.     if (code != newline) {
  512.     l_struct = false;
  513.     last_code = code;
  514.     }
  515.     if (buf_ptr >= buf_end)    /* check for input buffer empty */
  516.     fill_buffer();
  517.     ps.last_u_d = unary_delim;
  518.     *tok = '\0';        /* null terminate the token */
  519.     return (code);
  520. };
  521.  
  522. /* Add the given keyword to the keyword table, using val as the keyword type */
  523. void addkey(key, val)
  524.     char *key;
  525.     enum rwcodes val;
  526. {
  527.     register struct templ *p = specials;
  528.     while (p->rwd)
  529.     if (p->rwd[0] == key[0] && strcmp(p->rwd, key) == 0)
  530.         return;
  531.     else
  532.         p++;
  533.     if (p >= specials + sizeof specials / sizeof specials[0])
  534.     return;            /* For now, table overflows are silently
  535.                  * ignored */
  536.     p->rwd = key;
  537.     p->rwcode = val;
  538.     p[1].rwd = NULL;
  539.     p[1].rwcode = 0;
  540.     return;
  541. }
  542.